package com.lap.service.starter.api;

import com.lap.service.starter.tools.Constants;
import com.lap.service.starter.tools.UriUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
public class MappingRegistry {

  private static final Map<Class<? extends Annotation>, MappingProcessor> PROCESSOR_MAP =
      new HashMap<>();

  static {
    register(GetMapping.class, Constants.GET);
    register(PostMapping.class, Constants.POST);
    register(PutMapping.class, Constants.PUT);
    register(DeleteMapping.class, Constants.DELETE);
    register(PatchMapping.class, Constants.PATCH);

    // Optional fallback for unsupported mappings
    PROCESSOR_MAP.put(
        RequestMapping.class,
        (method, parentUri, apiDto) -> {
          log.warn("Unsupported mapping: {}", method.getName());
        });
  }

  private static void register(Class<? extends Annotation> clazz, String httpMethod) {
    PROCESSOR_MAP.put(
        clazz,
        (method, parentUri, apiDto) -> {
          Annotation mapping = method.getAnnotation(clazz);
          String[] values = getAnnotationValues(mapping);
          apiDto.setUri(UriUtil.getUri(parentUri, values));
          apiDto.setMethod(httpMethod);
          apiDto.setCode(UriUtil.getUriCode(apiDto.getModule(), apiDto.getUri(), httpMethod));
        });
  }

  private static String[] getAnnotationValues(Annotation annotation) {
    try {
      Method valueMethod = annotation.annotationType().getMethod("value");
      return (String[]) valueMethod.invoke(annotation);
    } catch (Exception e) {
      return new String[] {};
    }
  }

  public static boolean process(Method method, String parentUri, ApiResource apiResource) {
    for (Annotation annotation : method.getAnnotations()) {
      MappingProcessor processor = PROCESSOR_MAP.get(annotation.annotationType());
      if (processor != null) {
        processor.process(method, parentUri, apiResource);
        return true;
      }
    }
    return false;
  }
}
